using BepuPhysics;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif
namespace Demos.Demos.Tanks
{
    /// <summary>
    /// 将控制输入应用于坦克实例。
    /// </summary>
    public struct TankController
    {
        public Tank Tank;

        // 虽然Tank实例包含对所有包含模拟的内容的引用,但没有一个实例实际定义坦克的速度或强度。
        // 我们将其存储在控制器中,以便可以在飞翔上进行修改。
        public float Speed;
        public float Force;
        public float ZoomMultiplier;
        public float IdleForce;
        public float BrakeForce;

        // 如果约束目标已更改,则跟踪以前的状态以强制唤醒。
        private float previousLeftTargetSpeed;
        private float previousLeftForce;
        private float previousRightTargetSpeed;
        private float previousRightForce;
        private float previousTurretSwivel;
        private float previousBarrelPitch;

        public TankController(Tank tank,
            float speed, float force, float zoomMultiplier, float idleForce, float brakeForce) : this()
        {
            Tank = tank;
            Speed = speed;
            Force = force;
            ZoomMultiplier = zoomMultiplier;
            IdleForce = idleForce;
            BrakeForce = brakeForce;
        }

        /// <summary>
        /// 更新输入状态的约束目标。
        /// </summary>
        /// <param name="Simulation">包含坦克的模拟。</param>
        /// <param name="leftTargetSpeedFraction">左侧踏板最大速度的目标速度百分比。</param>
        /// <param name="rightTargetSpeedFraction">右踏板最大速度的目标速度百分比。</param>
        /// <param name="zoom">是否使用Boost倍增器。</param>
        /// <param name="brakeLeft">左踏板是否应该刹车。</param>
        /// <param name="brakeRight">右踏板是否应该刹车。</param>
        /// <param name="aimDirection">坦克桶应指向的方向。</param>
        public void UpdateMovementAndAim(Simulation simulation, float leftTargetSpeedFraction, float rightTargetSpeedFraction, bool zoom, bool brakeLeft, bool brakeRight, in Vector3 aimDirection)
        {
            var leftTargetSpeed = brakeLeft ? 0 : leftTargetSpeedFraction * Speed;
            var rightTargetSpeed = brakeRight ? 0 : rightTargetSpeedFraction * Speed;
            if (zoom)
            {
                leftTargetSpeed *= ZoomMultiplier;
                rightTargetSpeed *= ZoomMultiplier;
            }
            var leftForce = brakeLeft ? BrakeForce : leftTargetSpeedFraction == 0 ? IdleForce : Force;
            var rightForce = brakeRight ? BrakeForce : rightTargetSpeedFraction == 0 ? IdleForce : Force;

            var (targetSwivelAngle, targetPitchAngle) = Tank.ComputeTurretAngles(simulation, aimDirection);

            if (leftTargetSpeed != previousLeftTargetSpeed || rightTargetSpeed != previousRightTargetSpeed ||
                leftForce != previousLeftForce || rightForce != previousRightForce ||
                targetSwivelAngle != previousTurretSwivel || targetPitchAngle != previousBarrelPitch)
            {
                // 通过保护状态测试后面的约束修改,我们避免了每一帧都唤醒坦克。
                // (我们还可以使用ApplyDescriptionWithoutWking函数,然后在发生更改时显式唤醒存储箱。)
                Tank.SetSpeed(simulation, Tank.LeftMotors, leftTargetSpeed, leftForce);
                Tank.SetSpeed(simulation, Tank.RightMotors, rightTargetSpeed, rightForce);
                previousLeftTargetSpeed = leftTargetSpeed;
                previousRightTargetSpeed = rightTargetSpeed;
                previousLeftForce = leftForce;
                previousRightForce = rightForce;
                Tank.SetAim(simulation, targetSwivelAngle, targetPitchAngle);
                previousTurretSwivel = targetSwivelAngle;
                previousBarrelPitch = targetPitchAngle;
            }


        }
    }
}
